(function(w){
	//引用名
	var reference = "play";
	//旧的引用
	var oldReference = w[reference];
	//调试标记
	var debug = false;
	
	var exports = {};
	exports.result = null;
	exports.params = {};
	exports.request={};
	exports.session={};
	exports.container=null;
	exports.defaultHash=null;

	var hashChangeListeners = [];

	exports.onhashchange = function(listener){
		hashChangeListeners.push(listener);
	}

	var log = exports.log = function(msg){
		if(debug){
			console.log('[playframework] '+msg);
		}
	}

	exports.debug = function(){
		debug = true;
	}

	exports.getHash = function(){
		return window.location.hash.substring(1);
	}

	var JuicerResult = function(tmplId, args, init, destroy){
		var self = this;
		self.tmplId = tmplId;
		self.args = args;
		self.init = init;
		self.destroy = destroy;

		self.apply = function(){
			var tmpl = $(self.tmplId).html();
			return juicer(tmpl, self.args || {});
		}
	}

	var RouteResult = function(url){
		var self = this;
		self.url = url;

		self.apply = function(){
			window.location.hash = url;
		}
	}

	exports.Controller = (function(){
		var Controller = {};

		Controller.route = function(url){
			throw new RouteResult(url);
		}

		Controller.renderTemplate = function(tmplId, args, init, destroy){
			throw new JuicerResult(tmplId, args, init, destroy);
		}

		Controller.render = function(args, init, destroy){
			var path = '#' + exports.request.path;
			var defaultTmplId = path.replace('#/','#').replace('/','_');
			if($(defaultTmplId).length <= 0){
				log('Template ' + defaultTmplId + ' does not exist!');
			}
			if(typeof args == 'function'){
				throw new JuicerResult(defaultTmplId, {}, args, init);
			}else{
				throw new JuicerResult(defaultTmplId, args, init, destroy);
			}
		}

		Controller.renderTo = function(targetId, tmplId, args){
			var html = '';
			if($.isArray(args)){
				for(var i = 0; i < args.length; i ++){
					html += juicer($(tmplId).html(), args[i]);
				}
			}else{
				html = juicer($(tmplId).html(), args);
			}
			$(targetId).html(html);
		}

		return Controller;
	})();


	exports.router = (function(){
		var router = {};
		var routeMap = {};
		router.add = function(path, controllerObj){
			for(var i in controllerObj){
				var key = '/' + path + '/' + i;
				routeMap[key] = controllerObj[i];
				log('Route add ' + key);
			}
		}
		router.get = function(fullPath){
			return routeMap[fullPath];
		}
		return router;
	})();

	exports.noConflict = function() {
	    w[reference] = oldReference;
	    return exports;
	};

	var parseQuery = function(url){
		var result = {};
		var urlPartitions = url.split("?");
		result.path = urlPartitions[0];
		result.params = {};
		if(urlPartitions.length > 1){
			var str = urlPartitions[1], items = str.split("&");
			var arr;
			for (var i = 0; i < items.length; i++) {
				arr = items[i].split("=");
				result.params[arr[0]] = arr[1];
			}
		}
		
		return result;
	}

	var hashChanged = function(){
		var hash = exports.getHash();
		for(var i in hashChangeListeners){
			if(hashChangeListeners[i](hash)){
				return;
			}
		}
		var request = parseQuery(hash);
		exports.request = request;
		exports.params = request.params;
		var action = exports.router.get(request.path);
		if(!!action){
			try{
				action(request.params);
			}catch(e){
				if(!!e.apply){
					var html = e.apply();
					if(!!exports.result && !!exports.result.destroy){
						exports.result.destroy();
					}
					if(!!html){
						$(exports.container).html(html);
						exports.result = e;
						if(!!exports.result && !!exports.result.init){
							exports.result.init();
						}
					}
					
				}else{
					throw e;
				}
			}
		}else{
			log('Action ' + request.path + ' not found!');
			if(!!exports.defaultHash){
				window.location.hash = exports.defaultHash;
			}
		}
	}

	var addListener = function() {
		if (w.addEventListener) {
		  w.addEventListener('hashchange', hashChanged, false);
		} else {
		  w.attachEvent('onhashchange', hashChanged);
		}
	};

	exports.run = function(container, defaultHash){
		exports.container = container;
		if(!!defaultHash){
			exports.defaultHash = defaultHash;
		}
		addListener();
		hashChanged();
	}

	
	w[reference] = exports;
})(window);